﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ElasticMonads.Tests
{
    public struct Point
    {
        public int X { get; set; }
    }
    public class TestModel
    {
        public string Refrence { get; set; }
        public int Value { get; set; }

        public TestModel Complex { get; set; }
        public Point Struct { get; set; }
    }


    [TestClass]
    public class MaybeTests
    {
        #region property_tests
        #region not_null

        [TestMethod]
        public void Maybe_on_ref_property_not_null()
        {
            var model = new TestModel { Refrence = "ref" };
            Assert.AreEqual("ref", model.Maybe(x => x.Refrence));
        }

        [TestMethod]
        public void Maybe_on_val_property_not_null()
        {
            var model = new TestModel { Value = 5 };
            Assert.AreEqual(5, model.Maybe(x => x.Value));
        }

        [TestMethod]
        public void Maybe_on_complex_property_not_null()
        {
            var model = new TestModel { Complex = new TestModel() };
            Assert.IsNotNull(model.Maybe(x => x.Complex));
        }

        [TestMethod]
        public void Maybe_on_struct_property_not_null()
        {
            var model = new TestModel { Struct = new Point { X = 25 } };
            Assert.AreEqual(25, model.Maybe(x => x.Struct).X);
        }

        #endregion
        #region is_null

        [TestMethod]
        public void Maybe_on_ref_property_is_null()
        {
            var model = new TestModel();
            Assert.IsNull(model.Maybe(x => x.Refrence));
        }

        [TestMethod]
        public void Maybe_on_complex_property_is_null()
        {
            var model = new TestModel();
            Assert.IsNull(model.Maybe(x => x.Complex));
        }
        #endregion
        #endregion

        #region path_tests
        #region not_null

        [TestMethod]
        public void Maybe_on_ref_path_not_null()
        {
            var model = new TestModel { Refrence = "a" };
            Assert.AreEqual(1, model.Maybe(x => x.Refrence.Length));
        }

        [TestMethod]
        public void Maybe_on_complex_path_not_null()
        {
            var model = new TestModel { Complex = new TestModel { Refrence = "abc" } };
            Assert.AreEqual("abc", model.Maybe(x => x.Complex.Refrence));
        }
        [TestMethod]
        public void Maybe_on_struct_path_not_null()
        {
            var model = new TestModel { Struct = new Point { X = 25 } };
            Assert.AreEqual(25, model.Maybe(x => x.Struct.X));
        }
        #endregion

        #region is_null

        [TestMethod]
        public void Maybe_on_ref_path_is_null()
        {
            var model = new TestModel();
            Assert.AreEqual(0, model.Maybe(x => x.Refrence.Length));
        }

        [TestMethod]
        public void Maybe_on_complex_path_is_null()
        {
            var model = new TestModel();
            Assert.IsNull(model.Maybe(x => x.Complex.Refrence));
        }
        #endregion

        #endregion
    }

    [TestClass]
    public class DoTests
    {
        [TestMethod]
        public void Do_on_instance_not_null()
        {
            var model = new TestModel();
            model.Do(x => x.Refrence = "a");
            Assert.AreEqual("a", model.Refrence);
        }

        [TestMethod]
        public void Do_on_enumrable_not_null()
        {
            var array = new[] { 1, 2, 3 };
            var sum = 0;
            array.Do(x => sum += x);
            Assert.AreEqual(6, sum);
        }

        [TestMethod]
        public void Do_on_dictionary_not_null()
        {
            var dictionery = new Dictionary<int, int>
                {
                    {0,0},{1,1},{2,2}
                };
            var sum = 0;
            dictionery.Do((x, y) => sum += x + y);
            Assert.AreEqual(6, sum);
        }

        [TestMethod]
        public void Do_on_instance_is_null()
        {
            TestModel model = null;
            model.Do(x => x.Refrence = "a");
        }

        [TestMethod]
        public void Do_on_enumrable_is_null()
        {
            int[] array = null;
            var sum = 0;
            array.Do(x => sum += x);
        }

        [TestMethod]
        public void Do_on_dictionary_is_null()
        {
            Dictionary<int, int> dictionery = null;
            var sum = 0;
            dictionery.Do((x, y) => sum += x + y);
        }

    }

    [TestClass]
    public class ReturnTests
    {
        [TestMethod]
        public void Return_key_exits()
        {
            var dictionary = new Dictionary<int, int> { { 0, 1 } };
            Assert.AreEqual(1, dictionary.Return(0));
        }

        [TestMethod]
        public void Return_key_not_exits()
        {
            var dictionary = new Dictionary<int, int> { { 0, 1 } };
            Assert.AreEqual(0, dictionary.Return(10));
        }
    }
}
